// Package response http响应
package response

import (
	json2 "encoding/json"
	"errors"
	"github.com/goccy/go-json"
	"io"
	"net/http"
	"organoid_public/pkg/apperror"
	"organoid_public/pkg/logger"
	validator2 "organoid_public/pkg/validator"
	"strconv"

	"github.com/gin-gonic/gin"
	"github.com/go-playground/validator/v10"
)

// GinRestResponse gin restfull响应结构
type GinRestResponse struct {
	Code       int         `json:"code"`
	Message    string      `json:"message"`
	Data       interface{} `json:"data"`
	validate   *validator2.GinValidator
	ginContext *gin.Context
	log        logger.Logger
	payload    interface{}
}

const (
	// ErrorCodeValidateError 响应级错误参数校验不通过
	ErrorCodeValidateError = 400100

	// ErrorCodeLackRequiredParams 响应级错误缺少必要参数
	ErrorCodeLackRequiredParams = 400404
	ErrorCodeBindField          = 400400
)

// NewGinRestResponse 实例化gin restfull请求响应器
func NewGinRestResponse(log logger.Logger) *GinRestResponse {
	ginValidator, err := validator2.NewGinValidator()
	if err != nil {
		panic(apperror.NewAppError(500, "初始化验证器失败"))
	}
	if err != nil {
		return nil
	}
	return &GinRestResponse{
		Code:     0,
		Message:  "",
		Data:     nil,
		validate: ginValidator,
		log:      log,
	}
}

// New 每一个请求必须单独New
func (h *GinRestResponse) New(c *gin.Context) *GinRestResponse {
	return &GinRestResponse{
		validate:   h.validate,
		ginContext: c,
		log:        h.log,
	}
}

// Success 返回成功
func (h *GinRestResponse) Success(data interface{}) *GinRestResponse {
	h.Data = data
	h.Code = 0
	return h
}

// 返回错误
func (h *GinRestResponse) Error(err error) *GinRestResponse {
	h.Message = err.Error()
	h.Code = 500
	return h
}

// ErrorWithCode 设置错误码
func (h *GinRestResponse) ErrorWithCode(err string, code int) *GinRestResponse {
	h.Message = err
	h.Code = code
	return h
}

// ErrorWithMessage 设置错误消息
func (h *GinRestResponse) ErrorWithMessage(err string) *GinRestResponse {
	h.Message = err
	return h
}

// WithGinContext 绑定Gin请求上下文
func (h *GinRestResponse) WithGinContext(c *gin.Context) *GinRestResponse {
	h.ginContext = c
	return h
}

func (h *GinRestResponse) handleBindingError(err error, must bool) error {
	if errors.Is(err, io.EOF) {
		if must {
			h.Code = ErrorCodeLackRequiredParams
			h.Message = "缺少必要参数"
			h.ToJSON()
			return err
		}
		return nil
	}

	var validateErrors validator.ValidationErrors
	var bindErrors *json2.UnmarshalTypeError
	if errors.As(err, &validateErrors) {
		for _, item := range validateErrors {
			h.Code = ErrorCodeValidateError
			h.Message = item.Translate(h.validate.GetTranslator())
		}
	} else if errors.As(err, &bindErrors) {
		h.Code = ErrorCodeBindField
		h.Message = "请求参数类型错误"
	} else {
		h.Code = 500
		h.Message = err.Error()
	}

	h.ToJSON()
	return err
}

func (h *GinRestResponse) BindJSONWithValidate(data interface{}, must bool) error {
	err := h.ginContext.ShouldBindJSON(&data)
	if err != nil {
		return h.handleBindingError(err, must)
	}
	h.payload = data
	return nil
}

func (h *GinRestResponse) BindQueryWithValidate(data interface{}) error {
	err := h.ginContext.ShouldBindQuery(data)
	if err != nil {
		return h.handleBindingError(err, true)
	}
	h.payload = data
	return nil
}

func (h *GinRestResponse) BindWithValidate(data interface{}) error {
	err := h.ginContext.ShouldBind(data)
	if err != nil {
		return h.handleBindingError(err, true)
	}
	h.payload = data
	return nil
}

// ToJSONWithHTTPStatus 自定义http状态码
func (h *GinRestResponse) ToJSONWithHTTPStatus(httpStatus int) {
	h.ginContext.AbortWithStatusJSON(httpStatus, h)
}

// ToJSON 返回json
func (h *GinRestResponse) ToJSON() {
	l := map[string]interface{}{
		"url":     h.ginContext.Request.RequestURI,
		"method":  h.ginContext.Request.Method,
		"headers": h.ginContext.Request.Header,
		"payload": h.payload,
		"code":    h.Code,
		"message": h.Message,
		"data":    h.Data,
	}
	b, _ := json.Marshal(l)
	h.log.Info(string(b))
	h.ginContext.AbortWithStatusJSON(http.StatusOK, h)
}

// GetPage 接收query中的page参数
func (h *GinRestResponse) GetPage() uint {
	page := h.ginContext.DefaultQuery("page", "0")
	pageUint, err := strconv.ParseUint(page, 10, 64)
	if err != nil {
		h.Error(err).ToJSON()
		return 0
	}

	return uint(pageUint)
}

// GetValidator 获取验证器
func (h *GinRestResponse) GetValidator() *validator2.GinValidator {
	return h.validate
}
